#include <iostream>
#include <functional>
#include <map>
#include <string>
#include <mutex>
 
using namespace std;
template<class T>
class Singleton
{
public:
    static T& Instance()
    {
        if (m_gInstance == nullptr)
        {
            m_gInstanceMtx.lock();
            if (m_gInstance == nullptr)
                m_gInstance = new T();
            m_gInstanceMtx.unlock();
        }
        return *m_gInstance;
    }
    
    Singleton(const Singleton<T>&) = delete;
    Singleton(Singleton<T>&&) = delete;
    Singleton& operator=(const Singleton<T>&) = delete;
    friend typename T;
private:
    Singleton() {};
private:
    static T* m_gInstance;
    static std::mutex m_gInstanceMtx;
};
template<class T>
T* Singleton<T>::m_gInstance = nullptr;
template<class T>
std::mutex Singleton<T>::m_gInstanceMtx;

class Object: public Singleton<Object>
{
public:
    Object()
    {
        cout<<"Object is an Singleton now"<<endl;
    }
private:
    
};

//#define func std::function<void*(void)>
typedef void* (*func)(void);

class GenerateFactory
{
public:
    GenerateFactory(GenerateFactory&&)=delete;
    GenerateFactory(const GenerateFactory&)=delete;
    GenerateFactory& operator=(const GenerateFactory&)=delete;
    GenerateFactory& operator=(GenerateFactory&&)=delete;
 
    void* CreateTargetObj(const string &str)
    {
        for (auto & x : generators)
        {
            if(x.first == str){
                func f=x.second;
                return f();
            }
        }
        return nullptr;
    }
    // lambda表达式属于右值，如果想用引用接收，则形参应为右值引用类型
    void Register(const string &class_name, func && generator)
    {
        generators[class_name] = generator;
    }
 
    static std::shared_ptr<GenerateFactory> getSingleton()
    {
        static std::mutex mux;
        if(ptr == nullptr)
        {
            // 在多线程中获取单例，可能多次创建，因此加锁保护
            std::lock_guard<std::mutex> lock(mux);
            if(ptr == nullptr)
                ptr.reset(new GenerateFactory());
        }
        return ptr;
    }
 
    static GenerateFactory* getSingletonRawptr(){
        //实现lazy特性，线程安全，不用额外加锁保护，且还可以实现单例指针的自动回收
        if(rawInstance==nullptr){
            //在C++11标准中，要求编译器对局部静态变量初始化要具有线程安全性
            static SingleInstanceHolder holder;
            rawInstance = holder.instance;
        }
        return rawInstance;
    }
 
private:
    class SingleInstanceHolder{
    public:
        SingleInstanceHolder():instance(new GenerateFactory()){}
        ~SingleInstanceHolder(){
            if(instance!=nullptr&&instance==rawInstance)
                delete instance;
        }
    public:
        GenerateFactory* instance;
    };
 
 
private:
    GenerateFactory()=default;
 
    std::map<std::string, func> generators;
    //提供两种单例模式实现：(按需求选择一种就好了)
    static std::shared_ptr<GenerateFactory> ptr;//RAII 机制自动回收单例内存
    static GenerateFactory* rawInstance; //裸指针，借用内部类对象holder实现lazy模式并管理单例的生命周期
};
 
std::shared_ptr<GenerateFactory> GenerateFactory::ptr = nullptr;
GenerateFactory* GenerateFactory::rawInstance=nullptr;
 
 
class RegisterHelper
{
public:
    RegisterHelper(const string &class_name, func && generator)
    {
        GenerateFactory::getSingleton()->Register(class_name, std::forward<func>(generator));
        //GenerateFactory::getSingletonRawptr()->Register(class_name, std::forward<func>(generator));
    }
};
 
#define REGISTER_CLASS(CLASS_NAME) \
RegisterHelper g_register_##CLASS_NAME(#CLASS_NAME, []()->void* \
{\
    return new CLASS_NAME(); \
});
 
 
class Base
{
public:
    explicit Base() = default;
    virtual void Print()
    {
        cout << "Base" << endl;
    }
    virtual ~Base() {}
};
REGISTER_CLASS(Base)
 
class DeriverA : public Base
{
public:
    void Print() override
    {
        cout << "DeriverA" << endl;
    }
};
REGISTER_CLASS(DeriverA)
 
class DeriverB : public Base
{
public:
    void Print() override
    {
        cout << "DeriverB" << endl;
    }
};
REGISTER_CLASS(DeriverB)
 
 
int main(int argc, char *argv[])
{
    //func fPtr=[]()->void*{printf("hello world\n");return nullptr;};
    //fPtr();
 
    std::shared_ptr<GenerateFactory> fac = GenerateFactory::getSingleton();
    //GenerateFactory* fac = GenerateFactory::getSingletonRawptr(); //works fine.
    Base* t = (Base*)fac->CreateTargetObj("DeriverB");
    if(t==nullptr)
        printf("required class is not registered.\n");
    else
        t->Print();
    return 0;
}
